Each LScript that you select for execution is automatically filtered through the preprocessor, whether or not it contains any preprocessor-specific instructions or commands. The preprocessor is simply part of the process of compiling a script for execution.
All preprocessor directives in an LScript begin with an AT sign ('@
') in
column 1, followed by the directive name. For example:
// A simple script to rotate an object @warnings ...In older versions of LScript, the
#pragma
keyword was employed to provide
some of this functionality, and it can still appear in LScript files. However, it has
become obsolete, and support for it will be dropped in a future release of the LScript
engine. It's use is therefore discouraged.
The following compiler directives are recognized by the LScript preprocessor:
Insert files are used to house common commands and code that you wish to make availble to
two or more LScripts. This prevents you from not only having to duplicate script
code across all LScripts sharing the insert file, but greatly reduces the likelihood
that you will alter the functionality or meaning of data as you duplicate it.
Housing common code in an insert file also provides the advantage that updates can be
performed just once to all dependent scripts, in a single location.
You can insert files into your original scripts (and into other insert files, for that
matter, up to 30 levels deep!) by using the
Preprocessor directives continue to be evaluated and accumulated as each insert file
is processed.
The LScript preprocessor imposes no naming conventions on your include files. They
can be named in any fashion you wish, as long as the names are accurately provided
to the
Macros can also be embedded, which means that if a macro identifier appears in the value
of another macro identifier, then a substitution will take place on the embedded
identifier before the main identifier is substituted in the script code.
Preprocess macros are defined using the
Therefore, if the following line of script code were processed after the definition of
Let's see an example of this. If the following line of code were passed to a
traditional preprocessor (for instance, a C preprocessor), a compile-time error
would occur because the embedded identifier does not exist in a context wherein
it can be consider stand-alone (in other words, it is part of another identifier,
and becomes therefore inelligible):
Compiler Directives
A compiler directive is an instruction you give to a compiler or
interpreter to modify or affect its behavior. In LScript, each
compiler directive applies only to the LScript in which it appears.
warnings [count]
The warnings directive instructs LScript to bypass the
display of run-time warning messages. The optional count
parameter is an integer value that indicates the maximum number
of warnings that will be displayed.
Warning messages could be generated when a loss of data or an
unusual programming circumstance is detected by the
LScript engine during script execution. For instance, assigning
the return values of a user-defined procedure to an array
whose size is less than the count of return arguments is
always guaranteed to generate a warning message during an
LScript execution.
Warnings are turned off automatically in compiled scripts.
errors count
The errors directive provides to LScript the maximum
number of run-time error messages that will be displayed.
The count parameter is an integer value, and must be
provided. Error messages cannot be turned off, and the
count parameter cannot be zero (0).
Error messages are enabled in compiled scripts.
unused
During script development, it's possible to clutter your script
with unused variables. In large scripts, it can take a great
deal of time to locate and purge these "dead" variables.
The unused directive causes LScript to detect and report on
declared variables that are never used (i.e., assigned a value).
When your script has completed execution, LScript will display
a dialog window for each variable that it determined to be
unused.
This directive is intended as a support feature when the
strict directive is enabled, and then only as a
cleanup measure when script development is nearing completion.
It is not supported in compiled scripts nor in "lax" declaration
mode.
version {major.minor | "major.minor"}
The LScript engine provides for allowing scripts to specify
minimum versions of the LScript plug-in to be used to execute
the script. This is useful for scripts that have taken advantage
of newer features that would cause the script to fail to compile
on earlier versions of the plug-in.
Version indicators can be either literal floating-point values, or
literal string values. Only major and minor values, separated by
a period ('.'), will be considered valid by the interpreter.
autoerror
The normal practice for the LScript engine is to provide the
return value of all Layout- or Modeler-specific commands and
functions to the script. This allows the script to determine
if a command failed, and take actions that it deems appropriate.
However, there may be situations where the script programmer
does not care to add the extra code required to manage these
potential error conditions. In this case, the script programmer
can specify the autoerror directive. This directive instructs
LScript to handle these error conditions automatically, by issuing
an error message to the user, and terminating the script.
asyncspawn
LScript has the ability to launch external processes during a
script's execution (see the example LScript batch.ls for
an illustration of this capability). The default behavior of
the LScript engine is to execute these processes in a synchronous
fashion (i.e., halting execution of the LScript until the external
process has completed). However, there may be times when a
script programmer wishes to interact with an external process.
In this case, the script programmer needs to direct LScript to
launch external processes asynchronously, causing them to operate
in parallel with the LScript. The asyncspawn directive is
used in this situation.
nonrandom
The nonrandom directive will disable the random access to
ASCII text file lines that LScript affords to script programmers
through the use of its line() File Object Agent method. When
specified, LScript will not preprocess text files (those opened in
ASCII mode) to determine line offsets. Attempts to access the
line() method in a script where this pragma is employed will
result in a run-time error.
If your script tends to deal with large text files without the need
to randomly access lines, utilizing this directive will appreciably
increase the overall execution speed of your script.
literalpaths
Because LScript operates across (currently) three very-different
operating systems, it will automatically attempt to massage file
paths provided to functions suchs as matchfiles() and getfile()
into something more suitable for the current operating system. For
instance, under the Macintosh OS, UNIX forward slashes (/) and
MS-DOS back slashes (\) are converted into colons (:) because that
is the standard used by the Mac to separate directories.
The literalpaths directive disables this internal processing,
and causes the LScript engine to use file paths as they appear in
the script.
strict
LScript allows you to simply use variables and arrays whereever and
whenever you need them without having to explicitly declare them in
a previous 'var' statement (and in the case of arrays, without having
had to first explicitly declare an upper limit). However, there may be
times when you wish to add more structure to your script development
by requiring all variables and arrays to be explicitly declared. The
strict directive switches the LScript engine into a behavior
where variables and arrays are required to be explicitly declared
or sized in a var statement.
Regardless of the current declaration mode, multi-dimensional arrays
must always be explicitly declared.
Insert Files
Files can be "inserted" into your LScript at the time that it is compiled by the
LScript engine. These inserted files look to the engine as though they were simply
part of the original script (in fact, the preprocessor actually makes them
part of the original script before passing the final script off to the engine).
Inserted files can contain anything that a standard LScript can house, including
preprocessor commands.insert
directive
followed by a string literal that specifies the name of the file to be inserted:
...
@insert "myinc.lsi"
...
If an insert file does not contain an absolute path, the LScript preprocessor will
attempt to locate the script using the following steps:
1. Look in the current directory (which may or may not be the
same location as the script being executed)
2. Look in each directory specified in the LibPath configuration
element
If an insert file cannot be located, the LScript preprocessor will halt with an
error message, and the LScript engine will terminate.insert
directive.Preprocessor Macros
Preprocessor macros (or, manifest constants to the hard-core software developer)
behave very much like aliases. When a macro identifier is encountered in your
script code by the preprocessor, it substitutes the value of that macro identifier
for the identifier itself. This can prove handy for localizing code changes (instead
of having to change the value itself in numerous locations in the script), and for
making your script code more readable (i.e., "SELECT_SPHERE
" is a bit easier
to understand than "566
").define
directive, followed
by the macro identifier name and the value to be assigned to that identifier:
...
@define TOTAL_LIGHTS 100
...
In the above example, the identifier "TOTAL_LIGHTS
" is assigned a value of
100. If this identifier is encountered anywhere in the script code (or within code found
in a file inserted after the definition), the LScript preprocessor will substitute the
value in the output code before passing it to the LScript engine to be compiled.TOTAL_LIGHTS
:
...
for(x = 0;x < TOTAL_LIGHTS;x++)
...
the LScript engine would actually see:
...
for(x = 0;x < 100;x++)
...
Macro substitution occurs in the preprocessor before any other processing takes place.
High Visibility
LScript preprocessor macros have what is known as "high visibility." This means that,
while locating identifiers, the preprocess will not regard the context of the
identifier. Unless the identifier appears between open and close quotation marks (""),
the preprocessor will perform a substitution. This is contrary to traditional
preprocessors that require the identifier to be in a stand-alone context before
substitution will occur. Typically, punctuation marks and/or whitespace surrounding
the identifier are consider sufficient stand-alone context by traditional preprocessors.
#define ONEFIFTY 15
...
x = ONEFIFTY0; // <--- error! no such identifier "ONEFIFTY0"
However, LScript's preprocessor would handle the situation differently:
@define ONEFIFTY 15
...
x = ONEFIFTY0; // <--- assigns the value 150 to x
This method of high-visibility substitution can be powerful, but can also
cause you many difficulties if you happen to use script variable and function
identifiers that contain embedded macro names. Please keep this in mind while
writing your LScripts.Putting It All Together
Here is a rather-convoluted example that is both fully-functional and representative
of the capabilities of the LScript preprocessor.
@define SELECT 15
@define SELECT2 string("SELECT ",SELECT0)
@define SELECT3 "Bob!"
@define VERSION_DIRECTIVE version 1.0
@define BEGIN_BOBS_MAIN main {
@define END_BOBS_MAIN }
@define REM //
@insert "includes.h"
@VERSION_DIRECTIVE
@warnings
BEGIN_BOBS_MAIN
info(SELECT2); REM prints "SELECT 150"
info(SELECT2 + SELECT3); REM using string math, prints "SELECT 150Bob!"
END_BOBS_MAIN
Previous Section
Table of Contents
Index
Errata